home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Demos / Evatac Software / Preditor 3.0 / Tools / Language Module Builder / Sources / PascalParse.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-11-16  |  17.2 KB  |  885 lines  |  [TEXT/TCEd]

  1. /************************************************************
  2.  
  3.     PascalParse.c
  4.     C Source to Preditor 3
  5.  
  6.     Language Module Code for the "Pascal" language
  7.  
  8.     © Copyright Evatac Software  1988-1996
  9.     All rights reserved
  10.  
  11. ************************************************************/
  12.  
  13. #include "PascalParse.h"
  14. #include <SetupA4.h>
  15. #include <MixedMode.h>
  16. #include <Ctype.h>
  17.  
  18. #ifndef THINKC
  19. #include <A4Stuff.h>
  20. #else
  21. #define SetCurrentA4()    0; RememberA4()
  22. #define SetA4(x)        SetUpA4()
  23. #endif
  24.  
  25. #ifdef powerc
  26. ProcInfoType __procinfo = LanguageUPPInfo;
  27. #endif
  28.  
  29. static languageGlobals            globals;
  30. static ExternalCallbackBlock    *callbacks;
  31. static Boolean                    hadImplementation;
  32.  
  33.  
  34. /*
  35.  * * * *     PASCAL LANGUAGE ELECTRIC HANDLER       * * * * * *
  36.  */
  37.  
  38. static long _languageConvertToTabs(
  39.     Char    *text,
  40.     long     length,
  41.     long    hardTab
  42.     )
  43. {
  44.     int        tabs   = length / hardTab;
  45.     int        spaces = length % hardTab;
  46.     int        newLen = tabs + spaces;
  47.  
  48.     while (tabs-- > 0)
  49.         *(text++) = 9;
  50.     while (spaces-- > 0)
  51.         *(text++) = ' ';
  52.  
  53.     return(newLen);
  54. }
  55.  
  56. /*
  57.  * _languageHandleElectric
  58.  *
  59.  * We get called only when there is no selection, and one of the
  60.  * 3 electrics is pressed [;{}].
  61.  */
  62. static void _languageHandleElectric(
  63.     Char        ch
  64.     )
  65. {
  66.     long        anchor, end, pos, length;
  67.     long        i;
  68.     long        lineNumber, leading;
  69.     short        spacesPerTab, hardTab;
  70.     Char        text[256], *ptr = text;
  71.     
  72.     extGetSelection(callbacks, &anchor, &end);
  73.  
  74.     lineNumber = extLineFromPosition(callbacks, anchor);
  75.     leading    = extGetLeading(callbacks, lineNumber, &length,
  76.                                 &spacesPerTab, &hardTab);
  77.     
  78.     pos           = anchor;
  79.     anchor        = extLineToPosition(callbacks, lineNumber);
  80.     
  81.     /*
  82.      * Get the indentation of the current line
  83.      */
  84.     
  85.     if (ch == ';') {
  86.                 
  87.         /*
  88.          * Don't expand if we are in the middle a for statement.  Doesn't
  89.          * catch if for is not first word in line, or the (;;) expression
  90.          * spans multiple lines
  91.          */
  92.         
  93.         length = 256 - 4;
  94.         
  95.         extGetText(callbacks, anchor, end, text, &length);
  96.         text[length]   = 0;
  97.         text[length+1] = 0;
  98.         
  99.         while (*ptr == ' ' || *ptr == '\t')
  100.             ptr++;
  101.         ptr[3] = 0;
  102.         
  103.         if (languageCStringCompare(ptr, (Char *) "for") == 0) {
  104.         
  105.             /* 
  106.              * Check to see if we are passed the ')'
  107.              */
  108.             
  109.             ptr += 4;
  110.             
  111.             while (*ptr != 0) {
  112.                 if (*ptr == ')') 
  113.                     break;
  114.                 ptr++;
  115.             }
  116.             
  117.             if (*ptr == 0) {
  118.                 extInsert(callbacks, (Char *) ";", 1);
  119.                 return;
  120.             }
  121.         }
  122.         
  123.         /*
  124.          * Now create the text to insert
  125.          */
  126.         
  127.         text[0] = ';';
  128.         text[1] = '\r';
  129.         
  130.         i = _languageConvertToTabs(text + 2, leading, hardTab); 
  131.         
  132.         extInsert(callbacks, text, i + 2);
  133.     }
  134. }
  135.  
  136. /*
  137.  * * * *     PASCAL LANGUAGE INDENTING HANDLER       * * * * * *
  138.  */
  139.  
  140. /*
  141.  * _languageHandleIndent
  142.  *
  143.  * Indent the selected lines according to the buffer indentation settings
  144.  */
  145. static void _languageHandleIndent(
  146.     void        *extData
  147.     )
  148. {
  149.     long        anchor, end, pos, length;
  150.     long        lineStart;
  151.     long        i, x, newPos = -1;
  152.     long        lineNumber, endLineNumber, leading;
  153.     short        spacesPerTab, hardTab;
  154.     Char        text[256];
  155.     
  156.     extGetSelection(callbacks, &anchor, &end);
  157.  
  158.     if (anchor > end) {
  159.         pos = anchor; anchor = end; end = pos;   /* Swap */
  160.     }
  161.     
  162.     lineNumber    = extLineFromPosition(callbacks, anchor);
  163.     endLineNumber = extLineFromPosition(callbacks, end);
  164.  
  165.     /*
  166.      * Indent each line in the selection
  167.      */
  168.      
  169.     while (lineNumber <= endLineNumber) {
  170.         
  171.         if (lineNumber <= 1) {
  172.             lineNumber++;
  173.             continue;
  174.         }
  175.         
  176.         leading  = extGetLeading(callbacks, lineNumber, &length,
  177.                                    &spacesPerTab, &hardTab);
  178.     
  179.         lineStart = extLineToPosition(callbacks, lineNumber);
  180.         
  181.         /*
  182.          * Select the leading spaces/tabs
  183.          */
  184.          
  185.         extSetSelection(callbacks, lineStart, lineStart + length);
  186.  
  187.         /*
  188.          * Scan back previous lines for a line that we can relate to
  189.          */
  190.  
  191.         x = 1;
  192.  
  193.         for (;;) {
  194.  
  195.             if (lineNumber - x < 1)
  196.                 break;
  197.  
  198.             leading  = extGetLeading(callbacks, lineNumber - x, &length,
  199.                                        &spacesPerTab, &hardTab);
  200.                                        
  201.             end      = extLineEnd(callbacks, lineNumber - x);
  202.             pos         = extLineToPosition(callbacks, lineNumber - x);
  203.             
  204.             /* Skip Blank lines */
  205.  
  206.             if (length == (end - pos)) {
  207.                 x++;
  208.                 continue;
  209.                }
  210.             
  211.             i = pos + length;
  212.             
  213.             /*
  214.              * Perform Indention Smarts (Still under development)
  215.              */
  216.             
  217.             extScanContents(callbacks, i);
  218.             
  219.         /*    while (i++ < end && extNextScanCharacter(callbacks, &ch)) {
  220.                 
  221.                 if (ch == '{') {
  222.                     leading += spacesPerTab;
  223.                     break;
  224.                 }
  225.             } */
  226.             
  227.             extDoneScan(callbacks);
  228.  
  229.         
  230.             /*
  231.               * Indent the line
  232.              */
  233.             
  234.             i = _languageConvertToTabs(text, leading, hardTab); 
  235.         
  236.             extInsert(callbacks, text, i);
  237.             
  238.             if (newPos == -1)
  239.                 newPos = lineStart + i;
  240.             break;
  241.         }
  242.         
  243.         lineNumber++;
  244.     }
  245.  
  246.     if (newPos >= 0)
  247.         extSetSelection(callbacks, newPos, newPos);
  248. }
  249.  
  250. /*
  251.  * * * *     PASCAL LANGUAGE PARSER       * * * * * *
  252.  */
  253.  
  254. /*
  255.  * _languageBuildString
  256.  *
  257.  * Build up a literal string or literal contant "foo" or 'foo'
  258.  */
  259. static void _languageBuildString(
  260.     languageToken            *token,
  261.     int                        c
  262.     )
  263. {
  264.     Int32    index = 1, size = kTokenStringSize;
  265.     int        origC = c;
  266.     
  267.     token->string[1]     = c;
  268.     token->type = (c == '\"' ? kSymbolStringLiteral : kSymbolCharConstant);
  269.     
  270.     if (c == 'l' || c == 'L') {
  271.         
  272.         c = languageGetChar(&globals, callbacks);
  273.         token->string[0] = c;
  274.         index = 2;
  275.     }
  276.     
  277.     while ((c = languageGetChar(&globals, callbacks)) != -1) {
  278.         
  279.         if (index < size)
  280.             token->string[++index] = c;
  281.         
  282.         if (c == origC)
  283.             break;
  284.         
  285.         else if (c == '\\') {
  286.         
  287.             c = languageGetChar(&globals, callbacks);
  288.             
  289.             if (c != -1) {
  290.                 
  291.                 if (index < size)
  292.                     token->string[++index] = c;
  293.             }
  294.         }
  295.     }
  296.     
  297.     token->string[0] = index;        /* So string can be used as C or Pascal string */
  298.     token->string[++index] = 0;
  299. }
  300.  
  301. /*
  302.  * _languageBuildWhiteSpace
  303.  *
  304.  * Build up a directive (i.e. #define, etc)
  305.  */
  306. static void _languageBuildWhiteSpace(
  307.     languageToken             *token,
  308.     int                     c
  309.     )
  310. {
  311.     token->type = kSymbolWhiteSpace;
  312.  
  313.     while ((c = languageGetChar(&globals, callbacks)) != -1) {
  314.         
  315.         if (c != ' ' && c != '\t' && c != '\v' && c != '\n' &&
  316.             c != '\r' && c != '\f' && c != '\b') {
  317.     //    if (!isspace(c)) {
  318.             languageUngetChar(&globals, c);
  319.               return;
  320.         }
  321.     }
  322. }
  323.  
  324. /*
  325.  * _languageBuildComment
  326.  *
  327.  */
  328. static void _languageBuildComment(
  329.     languageToken             *token,
  330.     int                     c
  331.     )
  332. {
  333.     token->type                 = kSymbolComment;
  334.     globals.startLastComment     = globals.position;
  335.  
  336.     while ((c = languageGetChar(&globals, callbacks)) != -1) {
  337.     
  338.         if (c == '}')
  339.             break;
  340.     }
  341. }
  342.  
  343. /*
  344.  * _languageBuildNumber
  345.  *
  346.  */
  347. static void _languageBuildNumber(
  348.     languageToken             *token,
  349.     int                     c
  350.     )
  351. {
  352.     token->type = kSymbolIntConstant;
  353.  
  354.     if (c == '0') {
  355.     
  356.         c = languageGetChar(&globals, callbacks);
  357.  
  358.         if (c == 'x' || c == 'X') {
  359.         
  360.             while ((c = languageGetChar(&globals, callbacks)) != -1) {
  361.  
  362.                 if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'))
  363.                     ;
  364.                 else
  365.                     break;
  366.             }
  367.         }
  368.    
  369.         else {
  370.         
  371.             while (c != -1) {
  372.     
  373.                 if (c >= '0' && c <= '7')
  374.                     ;
  375.                 else
  376.                     break;
  377.         
  378.                 c = languageGetChar(&globals, callbacks);
  379.             }
  380.         }
  381.     }
  382.     
  383.     else {                                    /* decimal */
  384.  
  385.         while ((c = languageGetChar(&globals, callbacks)) != -1) {
  386.  
  387.             if (c >= '0' && c <= '9') 
  388.                 ;
  389.             else
  390.                 break;
  391.         }
  392.  
  393.         if (c == '.') {
  394.             
  395.             token->type = kSymbolFloatConstant;
  396.  
  397.             while ((c = languageGetChar(&globals, callbacks)) != -1) {
  398.             
  399.                 if (c >= '0' && c <= '9')
  400.                     ;
  401.                  else
  402.                     break;
  403.             }
  404.         }
  405.  
  406.         if (c == 'e' || c == 'E') {
  407.         
  408.             token->type = kSymbolFloatConstant;
  409.  
  410.             c = languageGetChar(&globals, callbacks);
  411.  
  412.             if (c == '-' || c == '+')
  413.                 c = languageGetChar(&globals, callbacks);
  414.  
  415.             while (c != -1) {
  416.  
  417.                 if (c >= '0' && c <= '9')
  418.                     ;
  419.                 else
  420.                     break;
  421.  
  422.                 c = languageGetChar(&globals, callbacks);
  423.             }
  424.         }
  425.     }
  426.  
  427.     while (c != -1) {
  428.         
  429.         if (c == 'l' || c == 'L' || c == 'u' || c == 'U' ||
  430.             c == 'f' || c == 'F' || c == 'h' || c == 'H')    
  431.             ;
  432.         else
  433.             break;
  434.         
  435.         c = languageGetChar(&globals, callbacks);
  436.     }
  437.     
  438.     if (c != -1)
  439.         languageUngetChar(&globals, c);
  440. }
  441.  
  442. /*
  443.  * _languageBuildWord
  444.  *
  445.  *
  446.  */
  447. static void _languageBuildWord(
  448.     languageToken             *token,
  449.     int                     c
  450.     )
  451. {
  452.     Int32            index = 1, size = kTokenStringSize;
  453.     Char            *scan, *target;
  454.     Char            lowerStr[kTokenStringSize + 2];
  455.     
  456.     token->type = kSymbolIdentifier;
  457.  
  458.     token->string[1] = c;
  459.     
  460.     while ((c = languageGetChar(&globals, callbacks)) != -1) {
  461.  
  462.         if (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c == '_'
  463.             || c >= '0' && c <= '9' || c == '.') {
  464.         
  465.             if (index < size)
  466.                 token->string[++index] = c;
  467.         }
  468.         else {
  469.         
  470.             languageUngetChar(&globals, c);
  471.             break;
  472.         }
  473.     }
  474.  
  475.     token->string[0] = index;        /* So string can be used as C or Pascal string */
  476.     token->string[++index] = 0;
  477.     
  478.     /*
  479.      * lower case the string for lookup
  480.      */
  481.      
  482.     scan   = token->string;
  483.     target = lowerStr;
  484.     
  485.     while (*scan != 0) {
  486.         *(target++) = tolower(*scan);
  487.         scan++;
  488.     }
  489.     *target = 0;
  490.     
  491.     /*
  492.      * Since hashing into a large reserved word table takes time, the reserved
  493.      * word table is not loaded for "function" scanning.  We do our own
  494.      * limited keyword check
  495.      */
  496.     
  497.     if (!languageHasTable(&globals)) {
  498.         
  499.         scan = lowerStr + 1;
  500.         
  501.         if (languageCStringCompare(scan, (Char *) "function") == 0)
  502.             token->type = kSymbolReservedWord;
  503.         else if (languageCStringCompare(scan, (Char *) "procedure") == 0)
  504.             token->type = kSymbolReservedWord;
  505.         else if (languageCStringCompare(scan, (Char *) "begin") == 0)
  506.             token->type = kSymbolReservedWord;
  507.         
  508.         return;
  509.     }
  510.     
  511.     else if (languageTableLookup((&globals), lowerStr + 1))
  512.         token->type = kSymbolReservedWord;
  513.     else if (languageCustomTableLookup((&globals), lowerStr + 1))
  514.         token->type = kSymbolCustomWord;
  515. }
  516.  
  517. /*
  518.  * _languageGetNextToken
  519.  */
  520. static languageToken *_languageGetNextToken(void)
  521. {
  522.     int                     first, second;
  523.     Int16                    previousType;
  524.     languageToken            *token = &globals.token;
  525.    
  526.     previousType            = token->type;
  527.     token->startLocation     = globals.position;
  528.     token->majorType        = -1;
  529.  
  530.     if ((first = languageGetChar(&globals, callbacks)) == -1)
  531.         return(nil);
  532.  
  533.     token->type             = first;
  534.  
  535.     second = languagePeekChar(&globals, callbacks);
  536.     
  537.     switch(first) {
  538.  
  539. /* "strings" */
  540. /* 'character constants' */
  541.  
  542.     case '\"':
  543.     case '\'':
  544.         _languageBuildString(token, first);
  545.         break;
  546.  
  547. /* white space */
  548.  
  549.     case ' ': case '\t': case '\v': case '\n': case '\r': case '\f': case '\b':
  550.         _languageBuildWhiteSpace(token, first);
  551.         break;
  552.  
  553. /* monographs */
  554.     case ';':
  555.         globals.startLastComment = -1;
  556.     case '(':
  557.     case '#':
  558.     case ')':
  559.     case '[':
  560.     case ']':
  561.     case '}':
  562.     case '~':
  563.     case '\\':
  564.     case ',':
  565.     case '?':
  566.     case '/':
  567.       break;
  568.  
  569. /* Comment */
  570.     case '{':
  571.         _languageBuildComment(token, first);
  572.         break;
  573.  
  574. /* *, *= */
  575.  
  576.     case '*':
  577.         if (second == '=') {
  578.             languageGetChar(&globals, callbacks);
  579.              token->type = kSymbolMultiplyAssign;
  580.          }
  581.      break;
  582.  
  583. /* %, %= */
  584.  
  585.     case '%':
  586.         if (second == '=') {
  587.             languageGetChar(&globals, callbacks);
  588.               token->type = kSymbolModAssign;
  589.         }
  590.         break;
  591.  
  592. /* !, != */
  593.  
  594.     case '!':
  595.            if (second == '=') {
  596.             languageGetChar(&globals, callbacks);
  597.               token->type = kSymbolNotEqual;
  598.         }
  599.         break;
  600.  
  601. /* &, &=, && */
  602.  
  603.     case '&':
  604.         if (second == '=') {
  605.             languageGetChar(&globals, callbacks);
  606.             token->type = kSymbolAndAssign;
  607.         }
  608.         else if (second == '&') {
  609.             languageGetChar(&globals, callbacks);
  610.             token->type = kSymbolAndAnd;
  611.         }
  612.         break;
  613.  
  614. /* |, ||, |= */
  615.  
  616.     case '|':
  617.         if (second == '=') {
  618.             languageGetChar(&globals, callbacks);
  619.             token->type = kSymbolOrAssign;
  620.         }
  621.            else if (second == '|') {
  622.             languageGetChar(&globals, callbacks);
  623.             token->type = kSymbolOrOr;
  624.         }
  625.     break;
  626.  
  627. /* +, ++, += */
  628.  
  629.     case '+':
  630.         if (second == '=') {
  631.             languageGetChar(&globals, callbacks);
  632.             token->type = kSymbolPlusAssign;
  633.         }
  634.         break;
  635.  
  636. /* -, --, -=, ->, ->* */
  637.  
  638.     case '-':
  639.         if (second == '=') {
  640.             languageGetChar(&globals, callbacks);
  641.             token->type = kSymbolMinusAssign;
  642.         }
  643.         else if (second == '>') {
  644.             languageGetChar(&globals, callbacks);
  645.             second = languagePeekChar(&globals, callbacks);
  646.  
  647.             if (second == '*') {
  648.                 languageGetChar(&globals, callbacks);
  649.                 token->type = kSymbolPointerStar;
  650.             }
  651.             else
  652.                 token->type = kSymbolPointer;
  653.         }
  654.         break;
  655.  
  656. /* ., .*, .NUM */
  657.  
  658.     case '.':
  659.         if (second == '*') {
  660.             languageGetChar(&globals, callbacks);
  661.             token->type = kSymbolDotStar;
  662.         }
  663.         
  664.         else if (second >= '0' && second <= '9')
  665.             _languageBuildNumber(token, first);
  666.             
  667.         else if (second == '.') {
  668.         
  669.             languageGetChar(&globals, callbacks);
  670.             
  671.             if (languagePeekChar(&globals, callbacks) == '.') {
  672.                 languageGetChar(&globals, callbacks);
  673.                 token->type = kSymbolEllipsis;
  674.              }
  675.              else {
  676.                  languageUngetChar(&globals, second);
  677.             }
  678.         }
  679.         break;
  680.  
  681. /* =, == */
  682.  
  683.     case '=':
  684.         if (second == '=') {
  685.             languageGetChar(&globals, callbacks);
  686.             token->type = kSymbolEqual;
  687.         }
  688.         break;
  689.  
  690. /* <, <<, <=, <<= */
  691.  
  692.     case '<':
  693.         if (second == '=') {
  694.             languageGetChar(&globals, callbacks);
  695.             token->type = kSymbolLessOrEqual;
  696.         }
  697.         else if (second == '>') {
  698.             languageGetChar(&globals, callbacks);
  699.             token->type = kSymbolNotEqual;
  700.         }
  701.         break;
  702.  
  703. /* >, >=, >>, >>= */
  704.  
  705.     case '>':
  706.         if (second == '=') {
  707.             languageGetChar(&globals, callbacks);
  708.             token->type = kSymbolGreaterOrEqual;
  709.         }
  710.         break;
  711.  
  712. /* ^, ^= */
  713.  
  714.     case '^':
  715.       if (second == '=') {
  716.           languageGetChar(&globals, callbacks);
  717.           token->type = kSymbolXOrAssign;
  718.     }
  719.       break;
  720.  
  721. /* :, := */
  722.  
  723.     case ':':
  724.         if (second == ':') {
  725.             languageGetChar(&globals, callbacks);
  726.               token->type = kSymbolAssign;
  727.         }
  728.         break;
  729.  
  730. /* the rest */
  731.  
  732.     default:
  733.         if (first >= '0' && first <= '9')
  734.             _languageBuildNumber(token, first);
  735.         else if (first >= 'a' && first <= 'z' || first >= 'A' && first <= 'Z' ||
  736.                  first == '_')
  737.                _languageBuildWord(token, first);
  738.  
  739.         /* Something weird, let the parser decide. */
  740.  
  741.         break;
  742.     }
  743.  
  744.     token->endLocation    = globals.position;
  745.     
  746.     return(token);
  747. }
  748.  
  749. void languageMain(
  750.     ExternalCallbackBlock    *extCallbacks,
  751.     WindowRef                window,
  752.     long                    options,
  753.     void                    *extData
  754.     );
  755.     
  756. /*
  757.  * languageMain
  758.  *
  759.  * This is the main entrypoint to the CODE module of a language module.
  760.  * The following operations are defined:
  761.  *
  762.  *     kLanguageParse        Parse the source file, returning positions of all tokens
  763.  *                        in the file.
  764.  *  kLanguageFunctions    Parse the source file, returning the position of just the
  765.  *                        functions in the source file
  766.  *  kLanguageIncludes    Parse the source file, returning the #include files
  767.  *  kLanguageTemplate    Expand macro -- insert template
  768.  *  kLanguageIndentLine
  769.  *    kLanguageElectric    Handle electric characters (i.e. }, {, ; )
  770.  */
  771.  
  772. void main(
  773.     ExternalCallbackBlock    *extCallbacks,
  774.     WindowRef                window,
  775.     long                    options,
  776.     void                    *extData
  777.     )
  778. {
  779.     languageToken        *token, tok, *saveToken = nil;
  780.     Int16                type;
  781.     Char                *ptr;
  782.     long                 saved_a4;
  783.  
  784.     saved_a4 = SetCurrentA4();
  785.     hadImplementation = true;
  786.  
  787.     languageInit(&globals, extCallbacks, options);
  788.  
  789.     callbacks    = extCallbacks;
  790.  
  791.     if (options == kLanguageTemplate) {
  792.  
  793.         languageDefaultHandler(&globals, callbacks, options, extData);
  794.     } 
  795.     
  796.     else if (options == kLanguageElectric) {
  797.         
  798.         _languageHandleElectric((Char) extData);
  799.     }
  800.     
  801.     else if (options == kLanguageIndent) {
  802.         
  803.         _languageHandleIndent(extData);
  804.     }
  805.     
  806.     else if (options <= kLanguageIncludes) {
  807.         
  808.         /*
  809.          * Now parse the file, returning a series of valid return token types:
  810.          *
  811.          *        kFunction
  812.          *         kKeyword
  813.          *         kComment
  814.          *        kCustomKeyword
  815.          */
  816.             
  817.         while ((token = _languageGetNextToken()) != nil) {
  818.         
  819.             type = token->type;
  820.             
  821.             if (type == kSymbolReservedWord) {
  822.             
  823.                 token->majorType = kKeyword;
  824.                 ptr                 = token->string;
  825.                 
  826.                 if (options == kLanguageParse)
  827.                     extTokenReturn(callbacks, token);
  828.                     
  829.                 if (hadImplementation &&
  830.                     (ptr[1] == 'f' && ptr[2] == 'u' ||
  831.                      ptr[1] == 'F' && ptr[2] == 'U'||
  832.                      ptr[1] == 'p' && ptr[4] == 'c'||
  833.                      ptr[1] == 'P' && ptr[4] == 'C')) {
  834.            
  835.                     _languageBuildWhiteSpace(token,
  836.                                              languageGetChar(&globals, callbacks));
  837.                     
  838.                     if ((token = _languageGetNextToken()) != nil) {
  839.         
  840.                         token->majorType        = kFunction;    
  841.                         token->commentLocation = globals.startLastComment;
  842.                         
  843.                         saveToken  = &tok;
  844.                         *saveToken = *token;
  845.                         
  846.                         token->majorType         = -1;
  847.                     }
  848.                     else
  849.                         continue;
  850.                 }
  851.                 else if (saveToken != nil && 
  852.                           (ptr[1] == 'b' || ptr[1] == 'B')) {
  853.                     
  854.                     if (options != kLanguageIncludes)
  855.                         extTokenReturn(callbacks, saveToken);
  856.                     saveToken = nil;
  857.                 }         
  858.             }
  859.         
  860.             else if (type == kSymbolCustomWord) {
  861.                 token->majorType = kCustomKeyword;
  862.             }
  863.  
  864.             else if (type == kSymbolComment)
  865.                 token->majorType = kComment;
  866.             
  867.             /*
  868.              * Only return a token if it's a interesting token, and
  869.              * if we are doing a full parse
  870.              */
  871.              
  872.             if (token->majorType >= 0 && options == kLanguageParse)
  873.                 extTokenReturn(callbacks, token);
  874.         }
  875.     }
  876.     
  877.     /*
  878.      * Clean up after ourselves
  879.      */
  880.  
  881.     languageDone(&globals, callbacks);
  882.     
  883.     SetA4(saved_a4);
  884. }
  885.